<!DOCTYPE html>
<title>WindowClient.navigate() on a prerendered iframe</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="utils.js"></script>
<script src="deferred-promise-utils.js"></script>
<body>
<script>
// The main test page loads the initiator page, then the initiator page will
// prerender itself with the `prerendering` parameter and add an iframe. Once
// the prerendered iframe is ready, post a message to a service worker to call
// WindowClient.navigate().

const IFRAME_URL = 'prerendered-iframe.html';

const params = new URLSearchParams(location.search);
const prerendering = params.has('prerendering');
const navigationUrl = params.get('navigationUrl');

function addIframe() {
  const iframe = document.createElement('iframe');
  iframe.src = IFRAME_URL;
  document.body.appendChild(iframe);
}

// If the navigation is expected to be deferred, wait to navigate to
// `navigationUrl` until a prerendered iframe is activated by
// PrerenderEventCollector. The result of the navigation is sent to
// "navigation-channel" BroadcastChannel and the prerendering states and events
// is sent to "test-channel" BroadcastChannel by PrerenderEventCollector.
async function startNavigationToCrossOriginUrl() {
  assert_not_equals(new URL(navigationUrl).origin, window.location.origin);

  const navigationPromise = new Promise(resolve => {
    const bc = new BroadcastChannel('navigation-channel');
    bc.addEventListener('message', e => {
      assert_equals(e.data, 'navigate() succeeded');
      resolve()
      bc.close();
    });
    navigator.serviceWorker.controller.postMessage({
      navigationUrl: navigationUrl,
      clientUrl: new URL(IFRAME_URL, window.location).toString(),
      respondTo: 'navigation-channel',
    });
  });

  const prerenderEventCollector = new PrerenderEventCollector();
  prerenderEventCollector.start(navigationPromise, 'navigation on iframe');
}

// If the navigation is expected to succeed without delay, the navigation result
// is directly sent to "test-channel" BroadcastChannel.
function startNavigationToSameOriginUrl() {
  assert_equals(new URL(navigationUrl).origin, window.location.origin);

  navigator.serviceWorker.controller.postMessage({
    navigationUrl: navigationUrl,
    clientUrl: new URL(IFRAME_URL, window.location).toString(),
    respondTo: 'test-channel',
  });
}

if (prerendering) {
  assert_not_equals(null, navigator.serviceWorker.controller,
      'should be controlled by a service worker');

  const bc = new BroadcastChannel('iframe-channel');
  const readyPromise = new Promise(resolve => {
    bc.addEventListener('message', e => {
      resolve(e.data);
    }, {
      once: true
    });
  });

  addIframe();

  readyPromise.then(result => {
    assert_equals(result, 'prerender success');

    if (new URL(navigationUrl).origin === window.location.origin) {
      startNavigationToSameOriginUrl();
    } else {
      startNavigationToCrossOriginUrl();
    }

    bc.close();
  });
} else {
  loadInitiatorPage();
}
</script>
</body>
